package net.esj.auth.inst.ssh.manage;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;

import net.esj.auth.AuthException;
import net.esj.auth.manager.AuthManager;
import net.esj.auth.pojo.CoreAdmin;
import net.esj.auth.pojo.CoreAdminFunc;
import net.esj.auth.pojo.CoreAdminFuncID;
import net.esj.auth.pojo.CoreAdminGroup;
import net.esj.auth.pojo.CoreAdminGroupID;
import net.esj.auth.pojo.CoreAuthFunc;
import net.esj.auth.pojo.CoreAuthGroup;
import net.esj.auth.pojo.CoreAuthModel;
import net.esj.basic.core.engine.support.MelonSupporter;
import net.esj.basic.core.engine.tools.crypt.inst.PwdEncryptor;
import net.esj.basic.core.view.tools.AgentContext;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.utils.Pagination;
import net.esj.basic.utils.Validators;

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class AuthManagerImpl extends DefaultServiceImpl implements AuthManager {

	protected boolean forcedDeleteGroup = false;
	protected boolean forcedDeleteFunc = false;

	
	@Override
	public void deleteAdmin(CoreAdmin admin) {
		//dao.execute("DELETE FROM CORE_ADMIN_FUNC WHERE  ADMIN_ID = '"+admin.getId()+"'");
		//dao.execute("DELETE FROM CORE_ADMIN_GROUP WHERE  ADMIN_ID = '"+admin.getId()+"'");
		//delete(admin);
		dao.execute("UPDATE CORE_ADMIN SET IS_DELETE = -1 WHERE ID = '"+admin.getId()+"'");
	}

	@Override
	public void deleteFunc(CoreAuthFunc func) throws AuthException {
		if(!isForcedDeleteGroup()){
			QueryBuilder<CoreAdminFunc> qb = createQueryBuilder(CoreAdminFunc.class);
			qb.eq("id.funcId", func.getId());
			int c = queryCountByQueryBuilder(qb);
			if(c>0){
				throw new AuthException("auth.func.used");
			}
		}
		delete(func);
		dao.execute("DELETE FROM CORE_ADMIN_FUNC WHERE  FUNC_ID = '"+func.getId()+"'");
	}

	private static final String COUNT_GROUP_ADMINS = "SELECT COUNT(1) FROM CORE_ADMIN_GROUP WHERE GROUP_ID =  ";
	
	@Override
	public String deleteGroup(CoreAuthGroup group) throws AuthException {
		if(!isForcedDeleteGroup()){
			StringBuilder sb = new StringBuilder(COUNT_GROUP_ADMINS);
			sb.append("'").append(group.getId()).append("'");
			List c = dao.query(sb.toString());
			Iterator iterator = c.iterator();
			int sum = 0;
			while (iterator.hasNext()) {
				sum = ((BigInteger) iterator.next()).intValue();
				//sum = (int) iterator.next();
			}	
			if(sum>0){
				throw new AuthException("auth.group.used");
			}
		}
		//delete(group);
		dao.execute("UPDATE CORE_AUTH_GROUP SET IS_DELETE = -1 WHERE ID = '"+group.getId()+"'");
		dao.execute("DELETE FROM CORE_ADMIN_GROUP WHERE GROUP_ID = '"+group.getId()+"'");
		return group.getName();
	}

	@Override
	public List<CoreAuthFunc> findFunctionsByParent(CoreAuthFunc parent) {
		QueryBuilder<CoreAuthFunc> qb = createQueryBuilder(CoreAuthFunc.class);
		qb.eq("parent", parent).OrderByAsc("sort");
		return queryListByQueryBuilder(qb);
	}

	@Override
	public List<CoreAuthFunc> findFunctions(CoreAuthFunc parent,CoreAuthModel model,int priority,boolean allChildren,boolean withDisabled) {
		QueryBuilder<CoreAuthFunc> qb = createQueryBuilder(CoreAuthFunc.class);
		if(parent==null){
			qb.isNull("parent");
		}else{
			qb.eq("parent", parent);
		}
		qb.eq("model", model).OrderByAsc("sort");
		if(priority>0){
			qb.eq("priority", priority);
		}
		if(!withDisabled){
			qb.eq("disabled", false);
		}
		List<CoreAuthFunc> funcs= queryListByQueryBuilder(qb);
		if(allChildren){
			for(CoreAuthFunc func: funcs){
				findChildren(func, priority,withDisabled);
			}
		}
		return funcs;
	}

	private void findChildren(CoreAuthFunc parent,int priority,boolean withDisabled){
		QueryBuilder<CoreAuthFunc> qb = createQueryBuilder(CoreAuthFunc.class);
		qb.eq("parent", parent).OrderByAsc("sort");
		if(priority>0){
			qb.eq("priority", priority);
		}
		if(!withDisabled){
			qb.eq("disabled", false);
		}
		List<CoreAuthFunc> funcs = queryListByQueryBuilder(qb);
		parent.setChildren(new LinkedHashSet<CoreAuthFunc>(funcs));
		for(CoreAuthFunc func : funcs){
			findChildren(func, priority,withDisabled);
		}
	}
	
	@Override
	public void grantFuncs(CoreAdmin admin, List<CoreAuthFunc> funcs) {
		//admin.setFunctions(new HashSet<CoreAuthFunc>(funcs));
		dao.execute("DELETE FROM CORE_ADMIN_FUNC WHERE ADMIN_ID  = '"+admin.getId()+"'");
		for(CoreAuthFunc fun : funcs){
			CoreAdminFunc af = new CoreAdminFunc();
			CoreAdminFuncID id = new CoreAdminFuncID(admin.getId(), fun.getId());
			af.setId(id);
			save(af);
		}
		//update(admin);
	}

	@Override
	public void grantGroups(CoreAdmin admin, List<CoreAuthGroup> groups) {
		dao.execute("DELETE FROM CORE_ADMIN_GROUP WHERE ADMIN_ID  = '"+admin.getId()+"'");
		for(CoreAuthGroup group : groups){
			CoreAdminGroup af = new CoreAdminGroup();
			CoreAdminGroupID id = new CoreAdminGroupID(admin.getId(), group.getId());
			af.setId(id);
			save(af);
		}
		//admin.setGroups(new HashSet<CoreAuthGroup>(groups));
		//update(admin);
	}

	@Override
	public void saveAuthGroupAndResetFuncs(CoreAuthGroup group) {
		saveOrUpdate(group);
	}

	@Override
	public void saveOrUpdateAdmin(CoreAdmin admin) {
		saveOrUpdate(admin);
	}

	@Override
	public void saveOrUpdateFunction(CoreAuthFunc func) {
		saveOrUpdate(func);
	}

	@Override
	public CoreAdmin getAdminWithAuth(String id) {
		CoreAdmin admin = get(id, CoreAdmin.class);
		QueryBuilder<CoreAdminFunc> qbf = createQueryBuilder(CoreAdminFunc.class);
		qbf.eq("admin", admin).fetch("func").eq("func.disabled", false);
		List<CoreAdminFunc> funcs = queryListByQueryBuilder(qbf);
		if(funcs.isEmpty()){
			admin.setFunctions(new HashSet<CoreAuthFunc>(0));
		}else{
			//admin.setFunctions(new HashSet<CoreAuthFunc>(0));
			for(CoreAdminFunc func:funcs){
				admin.getFunctions().add(func.getFunc());
			}
		}
		QueryBuilder<CoreAdminGroup> qbg = createQueryBuilder(CoreAdminGroup.class);
		qbg.eq("admin", admin).fetch("group");
		List<CoreAdminGroup> groups = queryListByQueryBuilder(qbg);
		if(groups.isEmpty()){
			admin.setGroups(new HashSet<CoreAuthGroup>(0));
		}else{
			for(CoreAdminGroup group:groups){
				admin.getGroups().add(group.getGroup());
			}
		}
		return admin;
	}
	
	@Override
	public boolean checkUsernameExist(String name) {
		QueryBuilder<CoreAdmin> qb = createQueryBuilder(CoreAdmin.class);
		qb.eq("name", name);
		return queryCountByQueryBuilder(qb)>0;
	}
	
	@Override
	@Transactional
	public CoreAuthModel saveOrUpdateModel(CoreAuthModel model) {
		saveOrUpdate(model);
		return model;
	}
	
	protected boolean  isForcedDeleteFunc(){
		return forcedDeleteFunc;
	}
	
	protected boolean  isForcedDeleteGroup(){
		return forcedDeleteGroup;
	}

	public void setForcedDeleteGroup(boolean forcedDeleteGroup) {
		this.forcedDeleteGroup = forcedDeleteGroup;
	}

	public void setForcedDeleteFunc(boolean forcedDeleteFunc) {
		this.forcedDeleteFunc = forcedDeleteFunc;
	}

	@Override
	public List<CoreAuthGroup> allGroup(CoreAuthModel model) {
		QueryBuilder<CoreAuthGroup> qb = createQueryBuilder(CoreAuthGroup.class);
		qb.eq("model", model);
		return queryListByQueryBuilder(qb);
	}
	
	@Override
	public Pagination<CoreAdmin> pageAdmin(Pagination page, CoreAdmin admin) {
		List<String> list = new ArrayList<String>();
		if(!admin.getName().equals(CoreAdmin.SUPER_ADMINISTRATOR_NAME)){
			list.add(admin.getId());
			list = getChildAdmin(admin.getId(),list);
			page.getQueryBuilder().eq("is_delete", 0).in("id", list);
		}else{
			page.getQueryBuilder().eq("is_delete", 0);
		}
		return queryPageByQueryBuilder(page);
	}
	
	@Override
	public List<String> getChildAdmin(String id,List<String> list) {
		QueryBuilder<CoreAdmin> qb = createQueryBuilder(CoreAdmin.class);
		qb.eq("creatorId", id);
		List<CoreAdmin> adminList = queryListByQueryBuilder(qb);
		for(CoreAdmin c : adminList){
			list.add(c.getId());
			list = getChildAdmin(c.getId(), list);
		}
		return list;
	}

	@Override
	public List<CoreAuthModel> allModels() {
		return findAll(CoreAuthModel.class);
	}

	protected PwdEncryptor getPwdEncryptor() {
		return MelonSupporter.getPwdEncryptor();
	}

	protected AgentContext getAgentContext() {
		return MelonSupporter.getViewer().getAgentContext();
	}

	@Override
	public CoreAdmin getAdminWithName(String name,String id) {
		QueryBuilder<CoreAdmin> qb = createQueryBuilder(CoreAdmin.class);
		qb.eq("name", name);
		CoreAdmin admin = (CoreAdmin) queryFirst(qb);
		if(!Validators.isEmpty(admin)){
			QueryBuilder<CoreAdminGroup> qb2 = createQueryBuilder(CoreAdminGroup.class);
			qb2.fetch("admin").eq("admin.id", admin.getId());
			List<CoreAdminGroup> list = queryListByQueryBuilder(qb2);
			for(CoreAdminGroup c : list){
				CoreAdminGroup g = new CoreAdminGroup();
				g.setId(new CoreAdminGroupID(id,c.getGroup().getId()));
				saveOrUpdate(g);
			}
			QueryBuilder<CoreAdminFunc> qb3 = createQueryBuilder(CoreAdminFunc.class);
			qb3.fetch("admin").eq("admin.id", admin.getId());
			List<CoreAdminFunc> list3 = queryListByQueryBuilder(qb3);
			for(CoreAdminFunc c : list3){
				CoreAdminFunc f = new CoreAdminFunc();
				f.setId(new CoreAdminFuncID(id,c.getFunc().getId()));
				saveOrUpdate(f);
			}
		}
		return admin;
	}

	@Override
	public List findMyFunctions(CoreAdmin admin) {
		admin = getAdminWithAuth(admin.getId());
		admin.getAllowedFunctions();
		return admin.getAllowedTree();
	}

	private List<CoreAuthFunc> setTree(List<CoreAuthFunc> list) {
		List<CoreAuthFunc> funcs = new ArrayList<CoreAuthFunc>();
		for(CoreAuthFunc c : list){
			if(Validators.isEmpty(c.getParent())){
				funcs.add(c);
			}
		}
		for(CoreAuthFunc c : list){
			if(!Validators.isEmpty(c.getParent())){
				Iterator<CoreAuthFunc> ite = funcs.iterator();
				while(ite.hasNext()){
					CoreAuthFunc f = ite.next();
					if(f.getId().equals(c.getParent().getId())){
						f.getChildren().add(c);
					}
				}
			}
		}
		
		return funcs;
	}

	@Override
	public List<CoreAuthGroup> listGroupByAdmin(List<String> list) {
		QueryBuilder<CoreAuthGroup> qb = createQueryBuilder(CoreAuthGroup.class);
		qb.in("createId", list).eq("isDelete", 0).eq("model.id", "CORE_ADMIN");
		return queryListByQueryBuilder(qb);
	}

	
}
